<?php namespace App\Core\Service\Services;

use DB;
use App\Core\Exceptions\InputError;
use App\Core\Repository\Criterias\FixedCriteria;

trait Changer{
    
    public $changeField;
    public $changeTo;
    public $changeFrom;
    public $changeWith;
    public $changeFields = [];
    public $changeData = [];
    public $changeModels;
    
    protected function change($field, $to, $from = '', $with = []){
        $this->changeField = $field;
        $this->changeTo = $to;
        $this->changeFrom = $from;
        $this->changeWith = $with;
        try {
            $this->getRepository()->addCriteria($this->getIndexCriteria());
            $this->changeGenerateFeilds();
            $this->fireEvent('changeGeneratedFeilds');
            $this->changeGenerateData();
            $this->fireEvent('changeGeneratedData');
            $this->changeValidate();
            if(!$this->validateRes['status']){
                $error = array_shift($this->validateRes['errors']);
                return $this->inputError('数据格式有误。字段'.$error[0].$error[1]);
            }
            if($from !== ''){
                $this->getRepository()->addCriteria(new FixedCriteria($field, $from));
            }
            $this->getRepository()->addCriteria($this->getIndexCriteria());
            $this->fireEvent('changeBeforeSave');
            $this->changeSaveData();
            $this->fireEvent('changeAfterSave');
            return $this->success();
		} catch (\Exception $ex) {
            if($ex instanceof InputError){
                return $this->inputError($ex->getMessage());
            }
            return $this->sysError($ex);
		}
    }
    
    protected function multiChange($field, $to = '', $from = '', $with = []){
        $this->changeField = $field;
        $this->changeTo = $to;
        $this->changeFrom = $from;
        $this->changeWith = $with;
        try {
            $this->getRepository()->addCriteria($this->getIndexesCriteria());
            $this->changeGenerateFeilds();
            $this->fireEvent('changeGeneratedFeilds');
            $this->changeGenerateData();
            $this->fireEvent('changeGeneratedData');
            $this->changeValidate();
            if(!$this->validateRes['status']){
                $error = array_shift($this->validateRes['errors']);
                return $this->inputError('数据格式有误。字段'.$error[0].$error[1]);
            }
            if($from !== ''){
                $this->getRepository()->addCriteria(new FixedCriteria($field, $from));
            }
            $this->getRepository()->addCriteria($this->getIndexesCriteria());
            $this->fireEvent('changeBeforeSave');
            $this->changeSaveData();
            $this->fireEvent('changeAfterSave');
            return $this->success();
		} catch (\Exception $ex) {
            throw $ex;
            return $this->sysError();
		}
    }
    
    protected function changeGenerateFeilds(){
        $fields = [$this->changeField];
        foreach($this->changeWith as $key => $val){
            if(is_numeric($key)){
                $fields[] = $val;
            }else{
                $fields[] = $key;
            }
        }
        return $this->changeFields = $fields;
    }
    
    protected function changeGenerateData(){
        $data = [$this->changeField => $this->changeTo];
        $fieldsWithoutValue = [];
        foreach($this->changeWith as $key => $val){
            if(is_numeric($key)){
                $fieldsWithoutValue[] = $val;
            }else{
                $data[$key] = $val;
            }
        }
        if($fieldsWithoutValue){
            $data = array_merge($data, $this->getMeta()->getData($fieldsWithoutValue));
        }
        return $this->changeData = $data;
    }
    
    protected function changeValidate(){
        $rules = $this->getMeta()->getRules($this->changeFields);
        $this->validateRes = $this->validator->validate($this->changeData, $rules);
    }
    
    protected function changeSaveData(){
        DB::beginTransaction();
        try {
            $this->fireEvent('changeSaving');
            $this->changeModels = $this->getRepository()->update($this->changeData);
            $this->fireEvent('changeSaved');
            DB::commit();
		} catch (\Exception $ex) {
            DB::rollBack();
			throw $ex;
        }
    }
}